/*********************************************************************

  This code fragment illustrates the unsuccessful attempt to directly
modify the IOPM base address.  This code would appear in a kernel
mode device driver.  Refer to the GIVEIO.C listing for a complete
device driver example.

*********************************************************************/

/*
 *  Make sure our structure is packed properly, on byte boundary, not
 * on the default doubleword boundary.
 */
#pragma pack(push,1)

/*
 *  Structure of a GDT (global descriptor table) entry.  From
 * processor manual.
 */
typedef struct {
	unsigned limit : 16;
	unsigned baselo : 16;
	unsigned basemid : 8;
	unsigned type : 4;
	unsigned system : 1;
	unsigned dpl : 2;
	unsigned present : 1;
	unsigned limithi : 4;
	unsigned available : 1;
	unsigned zero : 1;
	unsigned size : 1;
	unsigned granularity : 1;
	unsigned basehi : 8;
} GDTENT;

/*
 *  Structure of the 48 bits of the GDT register that are stored
 * by the SGDT instruction.
 */
typedef struct {
	unsigned short  limit;
	GDTENT  *base;
} GDTREG;

#pragma pack(pop)

/*
 *  This code demonstrates the brute force approach to modifying
 * the IOPM base.  The IOPM base is stored as a two byte integer
 * at offset 0x66 within the TSS, as documented in the processor
 * manual.  In Windows NT, the IOPM is stored within the TSS
 * starting at offset 0x88, and going for 0x2004 bytes.  This is
 * not documented anywhere, and was determined by inspection.
 * The code here puts some 0's into the IOPM so that we
 * can try to access some I/O ports, then modifies the IOPM base
 * address.
 *
 *  This code is unsuccessful because NT overwrites the IOPM
 * base on each process switch.
 */
void GiveIO()
{
	GDTREG gdtreg;
	GDTENT *g;
	short TaskSeg;
	char *TSSbase;
	int i;

	_asm str TaskSeg;                                       // get the TSS selector
	_asm sgdt gdtreg;                                       // get the GDT address

	g = gdtreg.base + (TaskSeg >> 3);       // get the TSS descriptor

										// get the TSS address
	TSSbase = (PVOID)(g->baselo | (g->basemid << 16) 
		       | (g->basehi << 24));

	for(i=0; i < 16; ++i)                           // poke some 0's into the
		TSSbase[0x88 + i] = 0;                  //   IOPM

										// set IOPM base to 0x88
	*((USHORT *)(TSSbase + 0x66)) = 0x88;
}

